/*
JETware Hands-free Extension provides additional features for Windows Mobile HFP support.
Copyright (C) 2004-2009 Jim Thatcher

This program is free software; you can redistribute it and/or modify it under the terms of the 
GNU General Public License as published by the Free Software Foundation; version 2 of the License.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 
without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program; 
if not, write to the Free Software Foundation, Inc., 
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

Source Control header

$Workfile: RegSettings.cpp $
$Revision: 26 $
$Date: 7/19/07 1:13p $
*/
// Include the proper version of TAPI
#include "stdafx.h"
#include <windows.h>
#include "BTHFExt.h"
#include "Ce_setup.h"
#include "version.h"
#include "shlobj.h"

#define JETWARE_ROOT	_T("SOFTWARE\\JETware")
#define JETWARE_KEY		_T("SOFTWARE\\JETware\\AGext")
#define JETWARE_MS		_T("SOFTWARE\\JETware\\AGext\\Messaging")
#define MSG_MAX			_T("MsgMax")
#define ALL_MSGS		_T("AllMsgs")
#define ONLY_NEW		_T("OnlyNew")
#define NOTIFY			_T("Notify")

#define FEATUREMASK _T("Flags")
#define CHAINMODULE		_T("BTAGExtChain")
#define PBMODULE		_T("BTAGPBModule")
#define EXTMODULE		_T("BTAGExtModule")
#define PBFILTER		_T("ContactFilter")
#define INCLUDE_NOCAT	_T("IncludeNoCat")
#define PBLIMIT_ME		_T("ContactLimit")
#define PBLIMIT_SM		_T("SimContactLimit")
#define PBLIMIT_DC		_T("DialedContactLimit")
#define PBLIMIT_RC		_T("IncomingContactLimit")
#define PBLIMIT_MC		_T("MissedContactLimit")
#define PBINCLUDE_FAX	_T("IncludeFaxNumbers")
#define INVERTROAM		_T("InvertRoam")
#define STATUSPOLL_INCALL	_T("InCallInterval")
#define STATUSPOLL_IDLE	_T("IdleInterval")
#define REPORT_IMI		_T("ReportIMI")
#define MFR_STRING		_T("MfrString")
#define MODEL_STRING	_T("ModelString")
#define SM_MSG_STORE	_T("SMMsgStore")
#define SM_MSG_MAX		_T("SMMsgMax")
#define SM_ALL_MSGS		_T("SMAllMsgs")
#define ME_MSG_STORE	_T("MEMsgStore")
#define ME_MSG_MAX		_T("MEMsgMax")
#define ME_ALL_MSGS		_T("MEAllMsgs")
#define PHONE_ID		_T("PhoneID")
// #define ACTIVATION_ID	_T("Prefix")
#define HACK_CHECK		_T("EnableAGExt")
// #define HACK_CHECK2		_T("FriendlyName")
// #define EVALUATION		_T("Evaluation")
#define HANDLE_CMER		_T("CMER")
#define HANDLE_CIND		_T("CIND")
#define HANDLE_CLIP		_T("CLIP")
#define HANDLE_CHUP		_T("CHUP")
#define HANDLE_CKPD		_T("CKPD")
#define HANDLE_CPMS		_T("CPMS")
#define HANDLE_CPBS		_T("CPBS")
// define KEY_VALUE		_T("Mode")
#define DEBUGLEVEL		_T("BTAGExtDebug")
#define POWER_REQ		_T("InSessionPower")
#define IN_BAND_RING	_T("InBandRingtone")
#define SLEEP_ON_DISCONNECT _T("SleepOnDisconnect")
#define REPORT_CID_NAME	_T("CIDNameFirst")
#define INIT_VOICE_DIAL	_T("StartVoiceDialAlias")
#define DEF_CHARSET		_T("DefaultCS")
#define MAX_PBNAME		_T("MaxPBName")
#define PS_RESUME		_T("PS1")
#define PS_SUSPEND		_T("PS0")
#define SHORT_RESPONSE	_T("SendLine")
#define PB_COUNT_TIME	_T("PBCountTimeout")

// Options to work around Parrot 3200LS phonebook bug that other phonebooks limited to number of SIM locations reported
#define PB_SWAP_ME_SM	_T("PWA1")
#define PB_REPORT_MAX	_T("PWA2")
DWORD g_dwPbSwapMeSm = 0;
DWORD g_dwReportSimMax = 0;

DWORD g_dwMaxPBName = 128;

TCHAR * g_szExtChainDll = NULL;
TCHAR * g_szContactFilter = NULL;
BOOL  g_bIncludeNoCat = FALSE;
DWORD g_dwIncludeFax = 0;
DWORD g_dwMaxContacts[8] = {NO_LIMIT,NO_LIMIT,NO_LIMIT,NO_LIMIT,NO_LIMIT,NO_LIMIT,NO_LIMIT,NO_LIMIT};
DWORD g_dwInvertRoam = 0;
DWORD g_dwInCallInterval = 2000;
DWORD g_dwIdleInterval = 5000;
DWORD g_dwReportIMI = 2;
// Options to select built-in, local, or combined handling of certain commands and reporting
DWORD g_dwHandleCMER = CMD_BOTH;
DWORD g_dwHandleCIND = CMD_BOTH;
DWORD g_dwHandleCLIP = CMD_INTERNAL_ONLY;
DWORD g_dwHandleCHUP = CMD_INTERNAL_ONLY;
DWORD g_dwHandleCKPD = CMD_INTERNAL_ONLY;
DWORD g_dwHandleCPBS = CMD_LOCAL_ONLY;
DWORD g_dwHandleCPMS = CMD_LOCAL_ONLY;
DWORD g_dwFeatureMask = 0;
DWORD g_dwInBandRing = 0;
DWORD g_dwSleepOnDisconnect = 0;
DWORD g_dwReportCIDName = FALSE;
DWORD g_dwShortResponse = FALSE;
DWORD g_dwPBCountTimeout = 5;

TCHAR * g_szMfrString = NULL;
TCHAR * g_szModelString = NULL;

TCHAR g_szPowerResumeName[16];
TCHAR g_szPowerSuspendName[16];

// TCHAR g_szHFDevName[64]; // FIX: 1.22
// BOOL  g_bDeviceChanged = FALSE;

BOOL GetDeviceRegSettings(TCHAR * szDeviceName);

void GetRegSettings()
{
    HRESULT hr                  = S_OK;
    HKEY    hKey                = NULL;
    DWORD   dwType              = 0;
	DWORD	dwSize				= 0;
	DWORD	wValue				= 0;
	TCHAR	szValue[MAX_PATH];
#ifdef DEBUG
	CHAR szLog[256];
#endif

    if (ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE, JETWARE_KEY, 0, 0, &hKey))
		goto Error;

	// read Resume power state string
	dwSize = sizeof(szValue);
	dwType = 0;
	wcscpy(g_szPowerResumeName, _T("On"));
    if (ERROR_SUCCESS == RegQueryValueEx(hKey, PS_RESUME, NULL, &dwType, (LPBYTE) &szValue, &dwSize))
	{
		if (dwSize && (dwType == REG_SZ))
		{
			memcpy(g_szPowerResumeName, szValue, dwSize);
#ifdef DEBUG
			sprintf(szLog, "\tResume power state=%ls", g_szPowerResumeName);
			LogString(szLog, DEBUG_INFO);
#endif
		}
	}
	// read Suspend power state string
	dwSize = sizeof(szValue);
	dwType = 0;
	wcscpy(g_szPowerSuspendName, _T("Unattended"));
    if (ERROR_SUCCESS == RegQueryValueEx(hKey, PS_SUSPEND, NULL, &dwType, (LPBYTE) &szValue, &dwSize))
	{
		if (dwSize && (dwType == REG_SZ))
		{
			memcpy(g_szPowerSuspendName, szValue, dwSize);
#ifdef DEBUG
			sprintf(szLog, "\tSuspend power state=%ls", g_szPowerSuspendName);
			LogString(szLog, DEBUG_INFO);
#endif
		}
	}
	// read ShortResponse (send each line separately)
	dwSize = sizeof(DWORD);
	wValue = 0;
	dwType = 0;
    RegQueryValueEx(hKey, SHORT_RESPONSE, NULL, &dwType, (LPBYTE) &wValue, &dwSize);
	if (dwSize && (dwType == REG_DWORD))
		g_dwShortResponse = wValue;
	else
		g_dwShortResponse = FALSE;
	// read in-band ringtone support
	dwSize = sizeof(DWORD);
	wValue = 0;
	dwType = 0;
    RegQueryValueEx(hKey, IN_BAND_RING, NULL, &dwType, (LPBYTE) &wValue, &dwSize);
	if (dwSize && (dwType == REG_DWORD))
		g_dwInBandRing = wValue;
	else
		g_dwInBandRing = TRUE;
	// read sleep-on-disconnect support
	dwSize = sizeof(DWORD);
	wValue = 0;
	dwType = 0;
    RegQueryValueEx(hKey, SLEEP_ON_DISCONNECT, NULL, &dwType, (LPBYTE) &wValue, &dwSize);
	if (dwSize && (dwType == REG_DWORD))
		g_dwSleepOnDisconnect = wValue;
	else
		g_dwSleepOnDisconnect = FALSE;
	// read feature mask
	dwSize = sizeof(DWORD);
	wValue = 0;
	dwType = 0;
    RegQueryValueEx(hKey, FEATUREMASK, NULL, &dwType, (LPBYTE) &wValue, &dwSize);
	if (dwSize && (dwType == REG_DWORD))
		g_dwFeatureMask = wValue;
	// read in-session power requirement
	dwSize = sizeof(DWORD);
	wValue = 0;
	dwType = 0;
    RegQueryValueEx(hKey, POWER_REQ, NULL, &dwType, (LPBYTE) &wValue, &dwSize);
	if (dwSize && (dwType == REG_DWORD))
		g_dwBagPowerReq = wValue;
	else
		g_dwBagPowerReq = -1; // PwrDeviceUnspecified
    // Get debug logging flags
	dwSize = sizeof(DWORD);
    RegQueryValueEx(hKey, DEBUGLEVEL, NULL, &dwType, (LPBYTE) &wValue, &dwSize);
	if (dwSize && (dwType == REG_DWORD))
	{
		g_dwDebugLevels = wValue;
// #ifdef DEBUG
		sprintf((CHAR *) szValue, "JetBTHFx v%d.%d.%d.%d initialized, Logging flags = %8.8X", VER_MAJOR, VER_MINOR, VER_BUILD, VER_BLD_MINOR, g_dwDebugLevels);
		LogString((CHAR *) szValue, DEBUG_INFO);
// #endif
	}
#ifdef DEBUG
	else
		LogString("No debug settings found in registry", DEBUG_INFO);
#ifdef DANGER
	HKEY hAGKey = NULL;
	if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, RK_AUDIO_GATEWAY, 0, 0, &hAGKey))
	{
		lstrcpy(szValue, _T("JetBTHFxg.dll"));
		RegSetValueEx(hAGKey, _T("BTAGPBModule"), 0, REG_SZ, (LPBYTE) &szValue, (lstrlen(szValue) + 1)*sizeof(TCHAR));
		RegCloseKey(hAGKey);
	}
#endif // DANGER
#endif // DEBUG
    // Get chain dll name, if one exists
	if (g_szExtChainDll == NULL)
	{
		// Chain module setting is in MS\Bluetooth\AudioGateway key
		HKEY hAGKey = NULL;

		if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, RK_AUDIO_GATEWAY, 0, 0, &hAGKey))
		{
			dwSize = sizeof(szValue);
			dwType = 0;
			if (ERROR_SUCCESS == RegQueryValueEx(hAGKey, CHAINMODULE, NULL, &dwType, (LPBYTE) &szValue, &dwSize))
			{
				if (dwSize && (dwType == REG_SZ))
				{
					g_szExtChainDll = (TCHAR *)LocalAlloc(LPTR, dwSize);
					memcpy(g_szExtChainDll, szValue, dwSize);
				}
			}
#ifdef DEBUG
			else
				LogString("No chain dll found in registry", DEBUG_CHAIN);
#endif
			RegCloseKey(hAGKey);
		}
		if (g_szExtChainDll == NULL) // FIX: 1.31: Treo 700wx relies on BAG service loading default named extension if one is not registered
		{
			g_szExtChainDll = (TCHAR *)LocalAlloc(LPTR, 24); // (wcslen(_T("btagext.dll"))+1)*sizeof(TCHAR));
			wcscpy(g_szExtChainDll, _T("btagext.dll"));
		}
	}
	// Read filter string for categories of contacts to send to phone
	dwSize = sizeof(szValue);
	dwType = 0;
    if (ERROR_SUCCESS == RegQueryValueEx(hKey, PBFILTER, NULL, &dwType, (LPBYTE) &szValue, &dwSize))
	{
		if (dwSize && (dwType == REG_SZ))
		{
			if (g_szContactFilter != NULL)
				LocalFree(g_szContactFilter);
			g_szContactFilter = (TCHAR *)LocalAlloc(LPTR, dwSize);
			memcpy(g_szContactFilter, szValue, dwSize);
#ifdef DEBUG
			sprintf(szLog, "\tContact filter=%ls", g_szContactFilter);
			LogString(szLog, DEBUG_INFO);
#endif
		}
		else if (g_szContactFilter != NULL)
		{
			LocalFree(g_szContactFilter);
			g_szContactFilter = NULL;
#ifdef DEBUG
			strcpy(szLog, "\tClearing contact filter");
			LogString(szLog, DEBUG_INFO);
#endif
		}
	}
	else if (g_szContactFilter != NULL)
	{
		LocalFree(g_szContactFilter);
		g_szContactFilter = NULL;
	}
	// read whether to include contacts with no categories in Outlook
	dwSize = sizeof(DWORD);
	wValue = 0;
	dwType = 0;
    RegQueryValueEx(hKey, INCLUDE_NOCAT, NULL, &dwType, (LPBYTE) &wValue, &dwSize);
	if (dwSize && (dwType == REG_DWORD))
		g_bIncludeNoCat = wValue;
	else
		g_bIncludeNoCat = FALSE;
	// read Manufacturer string returned from AT+CGMI
	dwSize = sizeof(szValue);
	dwType = 0;
    if (ERROR_SUCCESS == RegQueryValueEx(hKey, MFR_STRING, NULL, &dwType, (LPBYTE) &szValue, &dwSize))
	{
		if (dwSize && (dwType == REG_SZ))
		{
			if (g_szMfrString != NULL)
				LocalFree(g_szMfrString);
			g_szMfrString = (TCHAR *)LocalAlloc(LPTR, dwSize);
			memcpy(g_szMfrString, szValue, dwSize);
#ifdef DEBUG
			sprintf(szLog, "\tManufacturer is=%ls", g_szMfrString);
			LogString(szLog, DEBUG_INFO);
#endif
		}
		else if (g_szMfrString != NULL)
		{
			LocalFree(g_szMfrString);
			g_szMfrString = NULL;
		}
	}
	// read Model string returned from AT+CGMM
	dwSize = sizeof(szValue);
	dwType = 0;
    if (ERROR_SUCCESS == RegQueryValueEx(hKey, MODEL_STRING, NULL, &dwType, (LPBYTE) &szValue, &dwSize))
	{
		if (dwSize && (dwType == REG_SZ))
		{
			if (g_szModelString != NULL)
				LocalFree(g_szModelString);
			g_szModelString = (TCHAR *)LocalAlloc(LPTR, dwSize);
			memcpy(g_szModelString, szValue, dwSize);
#ifdef DEBUG
			sprintf(szLog, "\tModel is=%ls", g_szModelString);
			LogString(szLog, DEBUG_INFO);
#endif
		}
		else if (g_szModelString != NULL)
		{
			LocalFree(g_szModelString);
			g_szModelString = NULL;
		}
	}
	// Read settings for message access. Default: ME=ActiveSync, SM=SMS
	// read ME Store settings
	dwSize = sizeof(szValue);
	dwType = 0;
	if (g_szMsgStore[MESSAGES_ME] != NULL) // This should always be true
	{
		LocalFree(g_szMsgStore[MESSAGES_ME]);
		g_szMsgStore[MESSAGES_ME] = NULL;
	}
    if (ERROR_SUCCESS == RegQueryValueEx(hKey, ME_MSG_STORE, NULL, &dwType, (LPBYTE) &szValue, &dwSize))
	{
		if (dwSize && (dwType == REG_SZ))
		{
			g_szMsgStore[MESSAGES_ME] = (TCHAR *)LocalAlloc(LPTR, dwSize);
			memcpy(g_szMsgStore[MESSAGES_ME], szValue, dwSize);
		}
	}
	if (g_szMsgStore[MESSAGES_ME] == NULL) // Nothing in the registry, use default
	{
		g_szMsgStore[MESSAGES_ME] = (TCHAR *)LocalAlloc(LPTR, 24);
		lstrcpy(g_szMsgStore[MESSAGES_ME], _T("ActiveSync"));
	}
#ifdef DEBUG
	sprintf(szLog, "\tME message store=%ls", g_szMsgStore[MESSAGES_ME]);
	LogString(szLog, DEBUG_INFO);
#endif
	// read max messages for ME
	dwSize = sizeof(DWORD);
	wValue = 0;
	dwType = 0;
    RegQueryValueEx(hKey, ME_MSG_MAX, NULL, &dwType, (LPBYTE) &wValue, &dwSize);
	if (dwSize && (dwType == REG_DWORD))
		g_dwMsgMax[MESSAGES_ME] = wValue;
	// read whether to include read messages from ME store
	dwSize = sizeof(DWORD);
	wValue = 0;
	dwType = 0;
    RegQueryValueEx(hKey, ME_ALL_MSGS, NULL, &dwType, (LPBYTE) &wValue, &dwSize);
	if (dwSize && (dwType == REG_DWORD))
		g_bAllMsgs[MESSAGES_ME] = wValue;
	// Read SM store settings
	dwSize = sizeof(szValue);
	dwType = 0;
	if (g_szMsgStore[MESSAGES_SM] != NULL) // This should always be true
	{
		LocalFree(g_szMsgStore[MESSAGES_SM]);
		g_szMsgStore[MESSAGES_SM] = NULL;
	}
    if (ERROR_SUCCESS == RegQueryValueEx(hKey, SM_MSG_STORE, NULL, &dwType, (LPBYTE) &szValue, &dwSize))
	{
		if (dwSize && (dwType == REG_SZ))
		{
			g_szMsgStore[MESSAGES_SM] = (TCHAR *)LocalAlloc(LPTR, dwSize);
			memcpy(g_szMsgStore[MESSAGES_SM], szValue, dwSize);
		}
	}
	if (g_szMsgStore[MESSAGES_SM] == NULL) // Nothing in the registry, use default
	{
		g_szMsgStore[MESSAGES_SM] = (TCHAR *)LocalAlloc(LPTR, 8);
		lstrcpy(g_szMsgStore[MESSAGES_SM], _T("SMS"));
	}
#ifdef DEBUG
	sprintf(szLog, "\tSM message store=%ls", g_szMsgStore[MESSAGES_SM]);
	LogString(szLog, DEBUG_INFO);
#endif
	// read max messages for SM
	dwSize = sizeof(DWORD);
	wValue = 0;
	dwType = 0;
    RegQueryValueEx(hKey, SM_MSG_MAX, NULL, &dwType, (LPBYTE) &wValue, &dwSize);
	if (dwSize && (dwType == REG_DWORD))
		g_dwMsgMax[MESSAGES_SM] = wValue;
	// read whether to include read messages from SM store
	dwSize = sizeof(DWORD);
	wValue = 0;
	dwType = 0;
    RegQueryValueEx(hKey, SM_ALL_MSGS, NULL, &dwType, (LPBYTE) &wValue, &dwSize);
	if (dwSize && (dwType == REG_DWORD))
		g_bAllMsgs[MESSAGES_SM] = wValue;

	// read whether to include fax numbers to HF devices
	dwSize = sizeof(DWORD);
	wValue = 0;
	dwType = 0;
    RegQueryValueEx(hKey, PBINCLUDE_FAX, NULL, &dwType, (LPBYTE) &wValue, &dwSize);
	if (dwSize && (dwType == REG_DWORD))
		g_dwIncludeFax = wValue;
	else
		g_dwIncludeFax = 0;
	// read CMER handling
	dwSize = sizeof(DWORD);
	wValue = 0;
	dwType = 0;
    RegQueryValueEx(hKey, HANDLE_CMER, NULL, &dwType, (LPBYTE) &wValue, &dwSize);
	if (dwSize && (dwType == REG_DWORD))
		g_dwHandleCMER = wValue;
	else
		g_dwHandleCMER = CMD_BOTH;
	// read CIND handling
	dwSize = sizeof(DWORD);
	wValue = 0;
	dwType = 0;
    RegQueryValueEx(hKey, HANDLE_CIND, NULL, &dwType, (LPBYTE) &wValue, &dwSize);
	if (dwSize && (dwType == REG_DWORD))
		g_dwHandleCIND = wValue;
	else
		g_dwHandleCIND = CMD_BOTH;
	// read CLIP handling
	dwSize = sizeof(DWORD);
	wValue = 0;
	dwType = 0;
    RegQueryValueEx(hKey, HANDLE_CLIP, NULL, &dwType, (LPBYTE) &wValue, &dwSize);
	if (dwSize && (dwType == REG_DWORD))
		g_dwHandleCLIP = wValue;
	else
		g_dwHandleCLIP = CMD_INTERNAL_ONLY;
	// read CHUP handling
	dwSize = sizeof(DWORD);
	wValue = 0;
	dwType = 0;
    RegQueryValueEx(hKey, HANDLE_CHUP, NULL, &dwType, (LPBYTE) &wValue, &dwSize);
	if (dwSize && (dwType == REG_DWORD))
		g_dwHandleCHUP = wValue;
	else
		g_dwHandleCHUP = CMD_INTERNAL_ONLY;
	// read CKPD handling
	dwSize = sizeof(DWORD);
	wValue = 0;
	dwType = 0;
    RegQueryValueEx(hKey, HANDLE_CKPD, NULL, &dwType, (LPBYTE) &wValue, &dwSize);
	if (dwSize && (dwType == REG_DWORD))
		g_dwHandleCKPD = wValue;
	else
		g_dwHandleCKPD = CMD_INTERNAL_ONLY;
	// read CPMS handling
	dwSize = sizeof(DWORD);
	wValue = 0;
	dwType = 0;
    RegQueryValueEx(hKey, HANDLE_CPMS, NULL, &dwType, (LPBYTE) &wValue, &dwSize);
	if (dwSize && (dwType == REG_DWORD))
		g_dwHandleCPMS = wValue;
	else
		g_dwHandleCPMS = CMD_LOCAL_ONLY;
	// read CPBS handling
	dwSize = sizeof(DWORD);
	wValue = 0;
	dwType = 0;
    RegQueryValueEx(hKey, HANDLE_CPBS, NULL, &dwType, (LPBYTE) &wValue, &dwSize);
	if (dwSize && (dwType == REG_DWORD))
		g_dwHandleCPBS = wValue;
	else
		g_dwHandleCPBS = CMD_LOCAL_ONLY;
	// read Outlook Phonebook limit
	dwSize = sizeof(DWORD);
	wValue = 0;
	dwType = 0;
    RegQueryValueEx(hKey, PBLIMIT_ME, NULL, &dwType, (LPBYTE) &wValue, &dwSize);
	if (dwSize && (dwType == REG_DWORD))
		g_dwMaxContacts[CONTACTS_ME] = wValue;
	else
		g_dwMaxContacts[CONTACTS_ME] = NO_LIMIT;
	// read SIM Phonebook limit
	dwSize = sizeof(DWORD);
	wValue = 0;
	dwType = 0;
    RegQueryValueEx(hKey, PBLIMIT_SM, NULL, &dwType, (LPBYTE) &wValue, &dwSize);
	if (dwSize && (dwType == REG_DWORD))
		g_dwMaxContacts[CONTACTS_SM] = wValue;
	else
		g_dwMaxContacts[CONTACTS_SM] = NO_LIMIT;
	// read Dialed Call Phonebook limit
	dwSize = sizeof(DWORD);
	wValue = 0;
	dwType = 0;
    RegQueryValueEx(hKey, PBLIMIT_DC, NULL, &dwType, (LPBYTE) &wValue, &dwSize);
	if (dwSize && (dwType == REG_DWORD))
		g_dwMaxContacts[CONTACTS_DC] = wValue;
	else
		g_dwMaxContacts[CONTACTS_DC] = NO_LIMIT;
	// read Recieved Call Phonebook limit
	dwSize = sizeof(DWORD);
	wValue = 0;
	dwType = 0;
    RegQueryValueEx(hKey, PBLIMIT_RC, NULL, &dwType, (LPBYTE) &wValue, &dwSize);
	if (dwSize && (dwType == REG_DWORD))
		g_dwMaxContacts[CONTACTS_RC] = wValue;
	else
		g_dwMaxContacts[CONTACTS_RC] = NO_LIMIT;
	// read Missed Call Phonebook limit
	dwSize = sizeof(DWORD);
	wValue = 0;
	dwType = 0;
    RegQueryValueEx(hKey, PBLIMIT_MC, NULL, &dwType, (LPBYTE) &wValue, &dwSize);
	if (dwSize && (dwType == REG_DWORD))
		g_dwMaxContacts[CONTACTS_MC] = wValue;
	else
		g_dwMaxContacts[CONTACTS_MC] = NO_LIMIT;
	// read ReportIMI option - controls response to AT+CIMI - 1=report true IMI, 2=mask subscriber ID
	dwSize = sizeof(DWORD);
	wValue = 0;
	dwType = 0;
    RegQueryValueEx(hKey, REPORT_IMI, NULL, &dwType, (LPBYTE) &wValue, &dwSize);
	if (dwSize && (dwType == REG_DWORD))
		g_dwReportIMI = wValue;
	// read Report Caller ID Name option - for Nokia HS-12W, report CID name instead of number
	dwSize = sizeof(DWORD);
	wValue = 0;
	dwType = 0;
    RegQueryValueEx(hKey, REPORT_CID_NAME, NULL, &dwType, (LPBYTE) &wValue, &dwSize);
	if (dwSize && (dwType == REG_DWORD))
		g_dwReportCIDName = wValue;
	else
		g_dwReportCIDName = FALSE;
	// read Invert Roam option - Allows use of Roaming indicator on BMW to indicate connection
	dwSize = sizeof(DWORD);
	wValue = 0;
	dwType = 0;
    RegQueryValueEx(hKey, INVERTROAM, NULL, &dwType, (LPBYTE) &wValue, &dwSize);
	if (dwSize && (dwType == REG_DWORD))
		g_dwInvertRoam = wValue;
	// read in-call polling interval in milliseconds
	dwSize = sizeof(DWORD);
	wValue = 0;
	dwType = 0;
    RegQueryValueEx(hKey, STATUSPOLL_INCALL, NULL, &dwType, (LPBYTE) &wValue, &dwSize);
	if ((wValue > 0) && dwSize && (dwType == REG_DWORD))
		g_dwInCallInterval = wValue;
	// read idle polling interval in milliseconds
	dwSize = sizeof(DWORD);
	wValue = 0;
	dwType = 0;
    RegQueryValueEx(hKey, STATUSPOLL_IDLE, NULL, &dwType, (LPBYTE) &wValue, &dwSize);
	if ((wValue > 0) && dwSize && (dwType == REG_DWORD))
		g_dwIdleInterval = wValue;
	// read default character set
	dwSize = sizeof(DWORD);
	wValue = 0;
	dwType = 0;
    RegQueryValueEx(hKey, DEF_CHARSET, NULL, &dwType, (LPBYTE) &wValue, &dwSize);
	if ((wValue > 0) && dwSize && (dwType == REG_DWORD))
		g_wConvertToCharSet = (WORD) wValue;
	else
		g_wConvertToCharSet = CHARSET_GSM;
	// read maximum characters for Outlook phone book names
	dwSize = sizeof(DWORD);
	wValue = 0;
	dwType = 0;
    RegQueryValueEx(hKey, MAX_PBNAME, NULL, &dwType, (LPBYTE) &wValue, &dwSize);
	if (dwSize && (dwType == REG_DWORD))
		g_dwMaxPBName = min(wValue, 128);
	else
		g_dwMaxPBName = 128;
	// read Parrot work-around Swap ME-SM phone books
	dwSize = sizeof(DWORD);
	wValue = 0;
	dwType = 0;
    RegQueryValueEx(hKey, PB_SWAP_ME_SM, NULL, &dwType, (LPBYTE) &wValue, &dwSize);
	if (dwSize && (dwType == REG_DWORD))
		g_dwPbSwapMeSm = wValue;
	else
		g_dwPbSwapMeSm = FALSE;
	// read Parrot work around Report SM total as max SM ME total
	dwSize = sizeof(DWORD);
	wValue = 0;
	dwType = 0;
    RegQueryValueEx(hKey, PB_REPORT_MAX, NULL, &dwType, (LPBYTE) &wValue, &dwSize);
	if (dwSize && (dwType == REG_DWORD))
		g_dwReportSimMax = wValue;
	// read Phonebook Count timeout value
	dwSize = sizeof(DWORD);
	wValue = 0;
	dwType = 0;
    RegQueryValueEx(hKey, PB_COUNT_TIME, NULL, &dwType, (LPBYTE) &wValue, &dwSize);
	if (dwSize && (dwType == REG_DWORD))
		g_dwPBCountTimeout = wValue;
	else
		g_dwPBCountTimeout = 5;
	// Read number that, if "dialed" initiates voice dialing instead
	dwSize = sizeof(szValue);
	dwType = 0;
	if (g_szInitiateVoiceDialNumber != NULL)
	{
		LocalFree(g_szInitiateVoiceDialNumber);
		g_szInitiateVoiceDialNumber = NULL;
	}
    if (ERROR_SUCCESS == RegQueryValueEx(hKey, INIT_VOICE_DIAL, NULL, &dwType, (LPBYTE) &szValue, &dwSize))
	{
		if (dwSize && (dwType == REG_SZ))
		{
			g_szInitiateVoiceDialNumber = (CHAR *)LocalAlloc(LPTR, (dwSize/sizeof(TCHAR))+1);
			sprintf(g_szInitiateVoiceDialNumber, "%ls", (char *) szValue);
#ifdef DEBUG
			sprintf(szLog, "\tVoice dial number is=%s", g_szInitiateVoiceDialNumber);
			LogString(szLog, DEBUG_INFO);
#endif
		}
	}

Error:
    if (NULL != hKey)
    {
        RegCloseKey(hKey);
    }
	// now see if settings need to be overridden for device or phone compatibility
	//TCHAR szDeviceName[256];
	szValue[0] = 0;
	BOOL bFoundDeviceSettings = FALSE;
	if ((g_szMfrString != NULL) || (g_szModelString != NULL))
	{
		if (g_szMfrString != NULL)
			lstrcpy(szValue, g_szMfrString);
		if (g_szModelString != NULL)
		{
			lstrcat(szValue, _T(" "));
			lstrcat(szValue, g_szModelString);
		}
		if (szValue[0] != 0)
			bFoundDeviceSettings = GetDeviceRegSettings(szValue);
	}
	if (!bFoundDeviceSettings)
	{
		WORD wFlags = HWINFO_OEM;
		// Read from TAPI
		while (wFlags >= HWINFO_MFR)
		{
			szValue[0] = 0;
			ReadHardwareDeviceString(szValue, wFlags);
			if (szValue[0] != 0)
				bFoundDeviceSettings = GetDeviceRegSettings(szValue);
			if ((bFoundDeviceSettings) || (wFlags > HWINFO_OEM) || (wFlags < HWINFO_MFR))
				break;
			wFlags--;
		}
	}
	// Read currently connected HF device name from registry
	wsprintf(szValue, _T("%ls\\1"), RK_AUDIO_GATEWAY_DEVICES);

    if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, szValue, 0, 0, &hKey))
	{
		BYTE hfAddr[16];
		// Get Address from first device in AudioGateway Device list
		dwSize = sizeof(hfAddr);
		wValue = 0;
		dwType = 0;
		RegQueryValueEx(hKey, _T("Address"), NULL, &dwType, hfAddr, &dwSize);
		if (dwSize && (dwType == REG_BINARY))
		{
			wsprintf(szValue, _T("SOFTWARE\\Microsoft\\Bluetooth\\device\\%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X"),
				hfAddr[5], hfAddr[4], hfAddr[3], hfAddr[2], hfAddr[1], hfAddr[0]);
			RegCloseKey(hKey);

			if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, szValue, 0, 0, &hKey))
			{
				dwSize = sizeof(szValue);
				wValue = 0;
				dwType = 0;
				RegQueryValueEx(hKey, _T("name"), NULL, &dwType, (LPBYTE) &szValue, &dwSize);
				if (dwSize && (dwType == REG_SZ))
				{
#ifdef DEBUG
					sprintf(szLog, "Check device settings %ls", szValue);
					LogString(szLog, DEBUG_INFO);
#endif
					GetDeviceRegSettings(szValue);
					/* FIX: 1.22
					if (wcscmp(g_szHFDevName, szValue) != 0)
					{
						g_bDeviceChanged = TRUE;
						wcscpy(g_szHFDevName, szValue);
					}
					*/
				}
			}
		}
		if (hKey != NULL)
			RegCloseKey(hKey);
	}
}
// Some reg setting may be overridden based on phone or HFP device name for compatibiilty
BOOL GetDeviceRegSettings(TCHAR * szDeviceName)
{
    HRESULT hr                  = S_OK;
    HKEY    hKey                = NULL;
	BOOL	bReturn				= TRUE;
    DWORD   dwType              = 0;
	DWORD	dwSize				= 0;
	DWORD	wValue				= 0;
	TCHAR	szValue[256];
	CHAR szLog[256];
	wsprintf(szValue, _T("%ls\\%ls"), JETWARE_KEY, szDeviceName);

	sprintf(szLog, "Opening device reg key %ls", szValue);
	LogString(szLog, DEBUG_INFO);
    if (ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE, szValue, 0, 0, &hKey))
	{
		bReturn = FALSE;
		goto Error;
	}

#ifdef DEBUG
	sprintf(szLog, "Reading settings from %ls", szValue);
	LogString(szLog, DEBUG_INFO);
#endif
	// read ShortResponse (send each line separately)
	dwSize = sizeof(DWORD);
	wValue = 0;
	dwType = 0;
    RegQueryValueEx(hKey, SHORT_RESPONSE, NULL, &dwType, (LPBYTE) &wValue, &dwSize);
	if (dwSize && (dwType == REG_DWORD))
		g_dwShortResponse = wValue;
	// read in-band ringtone support
	dwSize = sizeof(DWORD);
	wValue = 0;
	dwType = 0;
    RegQueryValueEx(hKey, IN_BAND_RING, NULL, &dwType, (LPBYTE) &wValue, &dwSize);
	if (dwSize && (dwType == REG_DWORD))
		g_dwInBandRing = wValue;
	// read sleep-on-disconnect support
	dwSize = sizeof(DWORD);
	wValue = 0;
	dwType = 0;
    RegQueryValueEx(hKey, SLEEP_ON_DISCONNECT, NULL, &dwType, (LPBYTE) &wValue, &dwSize);
	if (dwSize && (dwType == REG_DWORD))
		g_dwSleepOnDisconnect = wValue;
	// read feature mask
	dwSize = sizeof(DWORD);
	wValue = 0;
	dwType = 0;
    RegQueryValueEx(hKey, FEATUREMASK, NULL, &dwType, (LPBYTE) &wValue, &dwSize);
	if (dwSize && (dwType == REG_DWORD))
	{
		if (wValue & FM_DEV_OVERRIDE)
			g_dwFeatureMask = wValue;
		else
			g_dwFeatureMask = g_dwFeatureMask | wValue; // Mask is union of main, phone, and device masks
	}
	// read in-session power requirement
	dwSize = sizeof(DWORD);
	wValue = 0;
	dwType = 0;
    RegQueryValueEx(hKey, POWER_REQ, NULL, &dwType, (LPBYTE) &wValue, &dwSize);
	if (dwSize && (dwType == REG_DWORD))
		g_dwBagPowerReq = wValue;
	// read Manufacturer string returned from AT+CGMI
	dwSize = sizeof(szValue);
	dwType = 0;
    if (ERROR_SUCCESS == RegQueryValueEx(hKey, MFR_STRING, NULL, &dwType, (LPBYTE) &szValue, &dwSize))
	{
		if (dwSize && (dwType == REG_SZ))
		{
			if (g_szMfrString != NULL)
				LocalFree(g_szMfrString);
			g_szMfrString = (TCHAR *)LocalAlloc(LPTR, dwSize);
			memcpy(g_szMfrString, szValue, dwSize);
#ifdef DEBUG
			sprintf(szLog, "\tManufacturer is=%ls", g_szMfrString);
			LogString(szLog, DEBUG_INFO);
#endif
		}
	}
	// read Model string returned from AT+CGMM
	dwSize = sizeof(szValue);
	dwType = 0;
    if (ERROR_SUCCESS == RegQueryValueEx(hKey, MODEL_STRING, NULL, &dwType, (LPBYTE) &szValue, &dwSize))
	{
		if (dwSize && (dwType == REG_SZ))
		{
			if (g_szModelString != NULL)
				LocalFree(g_szModelString);
			g_szModelString = (TCHAR *)LocalAlloc(LPTR, dwSize);
			memcpy(g_szModelString, szValue, dwSize);
#ifdef DEBUG
			sprintf(szLog, "\tModel is=%ls", g_szModelString);
			LogString(szLog, DEBUG_INFO);
#endif
		}
	}
	// read CMER handling
	dwSize = sizeof(DWORD);
	wValue = 0;
	dwType = 0;
    RegQueryValueEx(hKey, HANDLE_CMER, NULL, &dwType, (LPBYTE) &wValue, &dwSize);
	if (dwSize && (dwType == REG_DWORD))
		g_dwHandleCMER = wValue;
	// read CIND handling
	dwSize = sizeof(DWORD);
	wValue = 0;
	dwType = 0;
    RegQueryValueEx(hKey, HANDLE_CIND, NULL, &dwType, (LPBYTE) &wValue, &dwSize);
	if (dwSize && (dwType == REG_DWORD))
		g_dwHandleCIND = wValue;
	// read CLIP handling
	dwSize = sizeof(DWORD);
	wValue = 0;
	dwType = 0;
    RegQueryValueEx(hKey, HANDLE_CLIP, NULL, &dwType, (LPBYTE) &wValue, &dwSize);
	if (dwSize && (dwType == REG_DWORD))
		g_dwHandleCLIP = wValue;
	// read CHUP handling
	dwSize = sizeof(DWORD);
	wValue = 0;
	dwType = 0;
    RegQueryValueEx(hKey, HANDLE_CHUP, NULL, &dwType, (LPBYTE) &wValue, &dwSize);
	if (dwSize && (dwType == REG_DWORD))
		g_dwHandleCHUP = wValue;
	// read CKPD handling
	dwSize = sizeof(DWORD);
	wValue = 0;
	dwType = 0;
    RegQueryValueEx(hKey, HANDLE_CKPD, NULL, &dwType, (LPBYTE) &wValue, &dwSize);
	if (dwSize && (dwType == REG_DWORD))
		g_dwHandleCKPD = wValue;
	// read CPMS handling
	dwSize = sizeof(DWORD);
	wValue = 0;
	dwType = 0;
    RegQueryValueEx(hKey, HANDLE_CPMS, NULL, &dwType, (LPBYTE) &wValue, &dwSize);
	if (dwSize && (dwType == REG_DWORD))
		g_dwHandleCPMS = wValue;
	// read CPBS handling
	dwSize = sizeof(DWORD);
	wValue = 0;
	dwType = 0;
    RegQueryValueEx(hKey, HANDLE_CPBS, NULL, &dwType, (LPBYTE) &wValue, &dwSize);
	if (dwSize && (dwType == REG_DWORD))
		g_dwHandleCPBS = wValue;
	// read Outlook Phonebook limit
	dwSize = sizeof(DWORD);
	wValue = 0;
	dwType = 0;
	RegQueryValueEx(hKey, PBLIMIT_ME, NULL, &dwType, (LPBYTE) &wValue, &dwSize);
	if (dwSize && (dwType == REG_DWORD))
		g_dwMaxContacts[CONTACTS_ME] = wValue;
	// read SIM Phonebook limit
	dwSize = sizeof(DWORD);
	wValue = 0;
	dwType = 0;
	RegQueryValueEx(hKey, PBLIMIT_SM, NULL, &dwType, (LPBYTE) &wValue, &dwSize);
	if (dwSize && (dwType == REG_DWORD))
		g_dwMaxContacts[CONTACTS_SM] = wValue;
	// read Dialed Call Phonebook limit
	dwSize = sizeof(DWORD);
	wValue = 0;
	dwType = 0;
	RegQueryValueEx(hKey, PBLIMIT_DC, NULL, &dwType, (LPBYTE) &wValue, &dwSize);
	if (dwSize && (dwType == REG_DWORD))
		g_dwMaxContacts[CONTACTS_DC] = wValue;
	// read Recieved Call Phonebook limit
	dwSize = sizeof(DWORD);
	wValue = 0;
	dwType = 0;
	RegQueryValueEx(hKey, PBLIMIT_RC, NULL, &dwType, (LPBYTE) &wValue, &dwSize);
	if (dwSize && (dwType == REG_DWORD))
		g_dwMaxContacts[CONTACTS_RC] = wValue;
	// read Missed Call Phonebook limit
	dwSize = sizeof(DWORD);
	wValue = 0;
	dwType = 0;
	RegQueryValueEx(hKey, PBLIMIT_MC, NULL, &dwType, (LPBYTE) &wValue, &dwSize);
	if (dwSize && (dwType == REG_DWORD))
		g_dwMaxContacts[CONTACTS_MC] = wValue;
	// read Report Caller ID Name option - for Nokia HS-12W, report CID name instead of number
	dwSize = sizeof(DWORD);
	wValue = 0;
	dwType = 0;
    RegQueryValueEx(hKey, REPORT_CID_NAME, NULL, &dwType, (LPBYTE) &wValue, &dwSize);
	if (dwSize && (dwType == REG_DWORD))
		g_dwReportCIDName = wValue;
	// read default character set
	dwSize = sizeof(DWORD);
	wValue = 0;
	dwType = 0;
    RegQueryValueEx(hKey, DEF_CHARSET, NULL, &dwType, (LPBYTE) &wValue, &dwSize);
	if ((wValue > 0) && dwSize && (dwType == REG_DWORD))
		g_wConvertToCharSet = (WORD) wValue;
	// read maximum characters for Outlook phone book names
	dwSize = sizeof(DWORD);
	wValue = 0;
	dwType = 0;
    RegQueryValueEx(hKey, MAX_PBNAME, NULL, &dwType, (LPBYTE) &wValue, &dwSize);
	if (dwSize && (dwType == REG_DWORD))
		g_dwMaxPBName = min(wValue, 128);
	// read Parrot work-around Swap ME-SM phone books
	dwSize = sizeof(DWORD);
	wValue = 0;
	dwType = 0;
    RegQueryValueEx(hKey, PB_SWAP_ME_SM, NULL, &dwType, (LPBYTE) &wValue, &dwSize);
	if (dwSize && (dwType == REG_DWORD))
		g_dwPbSwapMeSm = wValue;
	// read Parrot work around Report SM total as max SM ME total
	dwSize = sizeof(DWORD);
	wValue = 0;
	dwType = 0;
    RegQueryValueEx(hKey, PB_REPORT_MAX, NULL, &dwType, (LPBYTE) &wValue, &dwSize);
	if (dwSize && (dwType == REG_DWORD))
		g_dwReportSimMax = wValue;
	// read Phonebook Count timeout value
	dwSize = sizeof(DWORD);
	wValue = 0;
	dwType = 0;
    RegQueryValueEx(hKey, PB_COUNT_TIME, NULL, &dwType, (LPBYTE) &wValue, &dwSize);
	if (dwSize && (dwType == REG_DWORD))
		g_dwPBCountTimeout = wValue;

Error:
    if (NULL != hKey)
    {
        RegCloseKey(hKey);
    }
	return(bReturn);
}

#ifdef __cplusplus
extern "C" {
#endif

typedef HANDLE _GetServiceHandle(LPWSTR szPrefix, LPWSTR szDllName, DWORD pdwDllBuf);
typedef HANDLE _RegisterService( LPCWSTR lpszType, DWORD dwIndex, LPCWSTR lpszLib,DWORD dwInfo);
typedef HANDLE _ActivateService(LPCWSTR lpszDevKey, DWORD dwClientInfo);
typedef BOOL _DeregisterService(HANDLE hDevice);

BOOL RestartBAG()
{
	BOOL bRet = FALSE;
	HINSTANCE hDll = LoadLibrary(_T("coredll.dll"));
	if (hDll != NULL)
	{
		_GetServiceHandle * GetServiceHandle = (_GetServiceHandle *) GetProcAddress(hDll, _T("GetServiceHandle"));
		_DeregisterService * DeregisterService = (_DeregisterService *) GetProcAddress(hDll, _T("DeregisterService"));
		_RegisterService * RegisterService = (_RegisterService *) GetProcAddress(hDll, _T("RegisterService"));
		_ActivateService * ActivateService = (_ActivateService *) GetProcAddress(hDll, _T("ActivateService"));
		HANDLE hService = GetServiceHandle(L"BAG0:", NULL, NULL);
		if(INVALID_HANDLE_VALUE != hService)
		{
			 DeregisterService(hService);
			 // Don't know if DerigisterService is synchronous
			 Sleep(2000);
			 hService = ActivateService(_T("BTAGSVC"), 0);
#ifdef DEBUG
			 CHAR szLog[64];
			 sprintf(szLog, "ActivateService returned 0x%8.8X", hService);
			 LogString(szLog, DEBUG_INFO);
#endif
			 if (hService != INVALID_HANDLE_VALUE)
				 bRet = TRUE;
		}
		FreeLibrary(hDll);
	}
	return bRet;
}

void CleanupShortcuts(HWND hWnd)
{
	TCHAR szLinkPath[256];
	TCHAR szStartMenu[MAX_PATH];
	TCHAR szPlatform[32];

	if (SystemParametersInfo(SPI_GETPLATFORMTYPE, sizeof(szPlatform), szPlatform, 0))
	{
		if (lstrcmp(szPlatform, TEXT("PocketPC")) == 0)
			g_bIsSmartPhone = FALSE;
	}

	BOOL bRet = SHGetSpecialFolderPath(hWnd, szStartMenu, CSIDL_STARTMENU, FALSE);
	if (!g_bIsSmartPhone)
	{
		bRet = SHGetSpecialFolderPath(hWnd, szStartMenu, CSIDL_PROGRAMS, FALSE);
		// lstrcat(szStartMenu, L"\\Programs");
	}
	lstrcat(szStartMenu, L"\\Bluetooth Options");

	wsprintf(szLinkPath, _T("%s\\Turn on Bluetooth.lnk"), szStartMenu);
	DeleteFile(szLinkPath);
#ifdef DEBUG
	CHAR szLog[MAX_PATH];
	g_dwDebugLevels |= DEBUG_INSTALL;
	sprintf(szLog, "Deleting shortcut %S", szLinkPath);
	LogString(szLog, DEBUG_INSTALL);
#endif

	wsprintf(szLinkPath, _T("%s\\Turn off Bluetooth.lnk"), szStartMenu);
	DeleteFile(szLinkPath);
#ifdef DEBUG
	sprintf(szLog, "Deleting shortcut %S", szLinkPath);
	LogString(szLog, DEBUG_INSTALL);
#endif

	wsprintf(szLinkPath, _T("%s\\Toggle Bluetooth.lnk"), szStartMenu);
	DeleteFile(szLinkPath);
#ifdef DEBUG
	sprintf(szLog, "Deleting shortcut %S", szLinkPath);
	LogString(szLog, DEBUG_INSTALL);
#endif
}


void CleanupInstallDir(LPCTSTR pszInstallDir)
{
	TCHAR szFileName[MAX_PATH];

	wcscpy(szFileName, pszInstallDir);
	lstrcat(szFileName, L"\\phonekey.txt");

	DeleteFile(szFileName);

	wcscpy(szFileName, pszInstallDir);
	lstrcat(szFileName, L"\\BTAGATLog.log");

	DeleteFile(szFileName);

	wcscpy(szFileName, pszInstallDir);
	lstrcat(szFileName, L"\\pb.vcf");

	DeleteFile(szFileName);
}


codeINSTALL_INIT Install_Init(HWND hwndParent, BOOL fFirstCall, BOOL fPreviouslyInstalled, LPCTSTR pszInstallDir)
{
	// Test for Microsoft BT stack - does it have btagsvc.dll
	HINSTANCE hDll = LoadLibrary(_T("btagsvc.dll"));
	if (hDll == NULL)
	{
		DWORD dwErr = GetLastError();
		if (dwErr == ERROR_FILE_NOT_FOUND)
		{
#ifdef DEBUG
			MessageBox(hwndParent, _T("btagsvc.dll"), _T("File not found"), MB_OK);
#endif
			MessageBox(hwndParent, _T("Your phone does not support the JETware Hands-free Extension"), _T("Installation failed"), MB_OK);
			return codeINSTALL_INIT_CANCEL;
		}
	}
	else
		FreeLibrary(hDll);
	return codeINSTALL_INIT_CONTINUE;
}

codeINSTALL_EXIT Install_Exit(HWND hwndParent, LPCTSTR pszInstallDir, WORD cFailedDirs, WORD cFailedFiles,
			 WORD cFailedRegKeys, WORD cFailedRegVals, WORD cFailedShortcuts)
{
    HRESULT hr                  = S_OK;
    HKEY    hKey                = NULL;
    DWORD   dwType              = 0;
	DWORD	dwSize				= 0;
	DWORD	dwRet				= 0;
	WORD	wValue				= 0;
	BOOL	bRegistered			= FALSE;
	BOOL	bFoundJetWare		= FALSE;
	TCHAR	szValue[256];
	TCHAR	szJetWareValue[256];
	TCHAR	szValueUpr[256];
#ifdef DEBUG
	CHAR szLog[256];
	g_dwDebugLevels |= DEBUG_INSTALL;
#endif

	if (ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE, RK_AUDIO_GATEWAY, 0, 0, &hKey))
		goto Error;

	dwSize = sizeof(szValue);
	dwRet = RegQueryValueEx(hKey, _T("JETwareModule"), NULL, &dwType, (LPBYTE) &szJetWareValue, &dwSize);
	if (dwRet == ERROR_SUCCESS)
		bFoundJetWare = TRUE;
	else
	{
#ifdef DEBUG
		sprintf(szLog, "Install Error: RegQueryValue for JETwareModule returned %8.8X", dwRet);
		LogString(szLog, DEBUG_INSTALL);
#endif
		goto Error;
	}
	// Get ext dll name, if one already exists
	// Try BTAGExtModule first - All devices will have that
	dwSize = sizeof(szValue);
	if (ERROR_SUCCESS == RegQueryValueEx(hKey, EXTMODULE, NULL, &dwType, (LPBYTE) &szValue, &dwSize))
	{
		if (dwSize && (dwType == REG_SZ))
		{
			wcscpy(szValueUpr, szValue);
			_wcsupr(szValueUpr);
			// only copy to CHAINMODULE if it isn't us
			if (wcsstr(szValueUpr, _T("JETBTHFX")) == NULL)
			{
				// write it to chain setting
				dwRet = RegSetValueEx(hKey, CHAINMODULE, 0, REG_SZ, (LPBYTE) &szValue, (lstrlen(szValue) + 1)*sizeof(TCHAR));
#ifdef DEBUG
				if (dwRet != 0)
				{
					sprintf(szLog, "Install Error: RegSetValue for Chain returned %8.8X", dwRet);
					LogString(szLog, DEBUG_INSTALL);
				}
#endif
				dwRet = RegSetValueEx(hKey, EXTMODULE, 0, REG_SZ, (LPBYTE) &szJetWareValue, (lstrlen(szJetWareValue) + 1)*sizeof(TCHAR));
				if (dwRet == 0)
					bRegistered = TRUE;
#ifdef DEBUG
				else
				{
					sprintf(szLog, "Install Error: RegSetValue for PBMODULE returned %8.8X", dwRet);
					LogString(szLog, DEBUG_INSTALL);
				}
#endif
			}
			else
			{
				if (wcsicmp(szJetWareValue, szValue) == 0)
					bRegistered = TRUE;
			}
		}
	}
/*
	// no longer a need to try the BTAGPBModule, we already found the ExtModule
	if (!bRegistered && (ERROR_SUCCESS == RegQueryValueEx(hKey, PBMODULE, NULL, &dwType, (LPBYTE) &szValue, &dwSize)))
	{
		if (dwSize && (dwType == REG_SZ))
		{
			wcscpy(szValueUpr, szValue);
			_wcsupr(szValueUpr);
			// only copy to CHAINMODULE if it isn't us
			if (wcsstr(szValueUpr, _T("JETBTHFX")) == NULL)
			{
				// write it to chain setting
				dwRet = RegSetValueEx(hKey, CHAINMODULE, 0, REG_SZ, (LPBYTE) &szValue, (lstrlen(szValue) + 1)*sizeof(TCHAR));
#ifdef DEBUG
				if (dwRet != 0)
				{
					sprintf(szLog, "Install Error: RegSetValue for Chain to EXTMODULE returned %8.8X", dwRet);
					LogString(szLog, DEBUG_INSTALL);
				}
#endif
				dwRet = RegSetValueEx(hKey, EXTMODULE, 0, REG_SZ, (LPBYTE) &szJetWareValue, (lstrlen(szJetWareValue) + 1)*sizeof(TCHAR));
				if (dwRet == 0)
					bRegistered = TRUE;
#ifdef DEBUG
				else
				{
					sprintf(szLog, "Install Error: RegSetValue for EXTMODULE returned %8.8X", dwRet);
					LogString(szLog, DEBUG_INSTALL);
				}
#endif
			}
			else
			{
				if (wcsicmp(szJetWareValue, szValue) == 0)
					bRegistered = TRUE;
			}
		}
	}
*/
	// No current PBMODULE or EXTMODULE
	if (!bRegistered)
	{
		dwRet = RegSetValueEx(hKey, EXTMODULE, 0, REG_SZ, (LPBYTE) &szJetWareValue, (lstrlen(szJetWareValue) + 1)*sizeof(TCHAR));
		if (dwRet == 0)
			bRegistered = TRUE;
#ifdef DEBUG
		else
		{
			sprintf(szLog, "Install Error: RegSetValue for EXTMODULE returned %8.8X", dwRet);
			LogString(szLog, DEBUG_INSTALL);
		}
#endif
	}

Error:
	if (NULL != hKey)
	{
		RegFlushKey(hKey);
		RegCloseKey(hKey);
	}

	if (bRegistered)
	{
		if (MessageBox(hwndParent, _T("Do you want to load the JETware Hands-free Extension now?\r\nThis will restart the Bluetooth Audio Gateway service."), _T("Install"), MB_YESNO) == IDYES)
		{
			RestartBAG();
		}
		return codeINSTALL_EXIT_DONE;
	}
	else if (bFoundJetWare)
		return codeINSTALL_EXIT_DONE;
	else
		return codeINSTALL_EXIT_UNINSTALL;
}

codeUNINSTALL_INIT Uninstall_Init(HWND hwndParent, LPCTSTR pszInstallDir)
{
    HRESULT hr                  = S_OK;
    HKEY    hKey                = NULL;
    DWORD   dwType              = 0;
	DWORD	dwSize				= 0;
	DWORD	dwRet				= 0;
	WORD	wValue				= 0;
	BOOL	bFoundPBModule		= FALSE;
	BOOL	bFoundJetWare		= FALSE;
	TCHAR	szJetWareValue[256];
	TCHAR	szValue[256];

	if (ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE, RK_AUDIO_GATEWAY, 0, 0, &hKey))
		goto CleanupJETware;

	dwSize = sizeof(szValue);
	dwRet = RegQueryValueEx(hKey, _T("JETwareModule"), NULL, &dwType, (LPBYTE) &szJetWareValue, &dwSize);
	if (dwRet == ERROR_SUCCESS)
		bFoundJetWare = TRUE;
	// Get ext dll name, if one already exists
	// Try BTAGPBModule first - WM 5 devices will have that
	dwSize = sizeof(szValue);
	if (ERROR_SUCCESS == RegQueryValueEx(hKey, PBMODULE, NULL, &dwType, (LPBYTE) &szValue, &dwSize))
	{
		if (dwSize && (dwType == REG_SZ))
		{
			if (bFoundJetWare && (wcsicmp(szJetWareValue, szValue) == 0))
			{
				bFoundPBModule = TRUE;
			}
			else
			{
				wcscpy(szJetWareValue, szValue); // Reuse variable since we are done with it
				_wcsupr(szJetWareValue);
				// only copy to CHAINMODULE if it isn't us
				if (wcsstr(szJetWareValue, _T("JETBTHFX")) == NULL)
					bFoundPBModule = TRUE;
			}
			if (bFoundPBModule)
			{
				dwSize = sizeof(szValue);
				RegQueryValueEx(hKey, CHAINMODULE, NULL, &dwType, (LPBYTE) &szValue, &dwSize);
				// write it to PBMODULE setting
				RegSetValueEx(hKey, PBMODULE, 0, REG_SZ, (LPBYTE) &szValue, (lstrlen(szValue) + 1)*sizeof(TCHAR));
			}
		}
	}
	// else try the BTAGExtModule
	if (!bFoundPBModule && (ERROR_SUCCESS == RegQueryValueEx(hKey, EXTMODULE, NULL, &dwType, (LPBYTE) &szValue, &dwSize)))
	{
		if (dwSize && (dwType == REG_SZ))
		{
			dwSize = sizeof(szValue);
			RegQueryValueEx(hKey, CHAINMODULE, NULL, &dwType, (LPBYTE) &szValue, &dwSize);
			// write it to PBMODULE setting
			RegSetValueEx(hKey, EXTMODULE, 0, REG_SZ, (LPBYTE) &szValue, (lstrlen(szValue) + 1)*sizeof(TCHAR));
		}
	}
	RegDeleteValue(hKey, CHAINMODULE);

	if (NULL != hKey)
	{
		RegFlushKey(hKey);
		RegCloseKey(hKey);
		hKey = NULL;
	}

CleanupJETware:
	if (ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE, JETWARE_ROOT, 0, 0, &hKey))
		goto Error;
	RegDeleteKey(HKEY_LOCAL_MACHINE, JETWARE_KEY);
	if (ERROR_SUCCESS == RegQueryInfoKey(hKey, NULL, NULL, NULL, &dwSize, NULL, NULL, NULL, NULL, NULL, NULL, NULL))
	{
		if (dwSize == 0)
		{
			RegCloseKey(hKey);
			hKey = NULL;
			RegDeleteKey(HKEY_LOCAL_MACHINE, JETWARE_ROOT);
			RegFlushKey(HKEY_LOCAL_MACHINE);
		}
	}
	// Delete HACK_CHECK, but leave eval backup appended to FriendlyName to limit evaluation to 30 days even across uninstall/reinstall
	if (NULL != hKey)
	{
		RegFlushKey(hKey);
		RegCloseKey(hKey);
	}
	if (ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE, RK_AG_SERVICE, 0, 0, &hKey))
		goto Error;
	RegDeleteValue(hKey, HACK_CHECK);
Error:
	if (NULL != hKey)
	{
		RegFlushKey(hKey);
		RegCloseKey(hKey);
	}
	CleanupShortcuts(hwndParent);
	CleanupInstallDir(pszInstallDir);
	RestartBAG();

	return codeUNINSTALL_INIT_CONTINUE;
}

codeUNINSTALL_EXIT Uninstall_Exit(HWND hwndParent)
{
	return codeUNINSTALL_EXIT_DONE;
}


#ifdef __cplusplus
}
#endif


